﻿using System;
using System.Linq;
using System.Media;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.IO;
using LSA.Framework;
using System.Collections.Generic;

namespace Visuals
{
    /// <summary>
    /// Interaction logic for SearchPreview.xaml
    /// </summary>

    public partial class SearchPreview : Window
    {
        private LsaSpace lsaSpace;
        public string[] FilePaths { get; set; }
        private List<TextPointer> pointers;
        private int pointerCount;
        private int lastDoc = -2;
        
        public SearchPreview(LsaSpace lsaSpaceParam)
        {
            InitializeComponent();
            lsaSpace = lsaSpaceParam;
            foreach (KeyValuePair<string, byte> entity in lsaSpace.Entities)
            {
                listView.Items.Add(entity);
            }
        }

        private void listViewResults_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (listView.SelectedItem == null)
            return;
            comboBoxCategory.SelectedIndex = ((KeyValuePair<string, byte>) listView.SelectedItem).Value;
        }

        public bool DoSearch(RichTextBox richTextBox, string searchText, bool searchNext)
        {
            TextPointer position = richTextBoxPreview.Document.ContentStart;
            TextRange range = FindWordFromPosition(position, textBoxSearchBox.Text);
            if (range == null)
                return false;
            position = range.End;

            pointers = new List<TextPointer>();
            pointerCount = 0;
            
            while (range.End.CompareTo(richTextBoxPreview.Document.ContentEnd) < 0)
            {
                pointers.Add(range.Start);

                richTextBox.Selection.Select(range.Start, range.End);
                richTextBox.Selection.ApplyPropertyValue(TextElement.ForegroundProperty, new SolidColorBrush(Colors.Red));
                richTextBox.Selection.ApplyPropertyValue(TextElement.FontWeightProperty, FontWeights.Bold);
                richTextBox.Selection.ApplyPropertyValue(TextElement.FontSizeProperty, 13.0);

                range = FindWordFromPosition(position, textBoxSearchBox.Text);
                if (range == null)
                    return false;
                position = range.End;
            }

            return true;
        }

        public void ScrollToNext(RichTextBox richTextBox)
        {
            if (pointerCount > pointers.Count - 1)
            {
                pointerCount = 0;
            }

            Rect screenPos = pointers[pointerCount].GetCharacterRect(LogicalDirection.Forward);
            double offset = screenPos.Top + richTextBox.VerticalOffset;
            richTextBox.ScrollToVerticalOffset(offset - richTextBox.ActualHeight / 2);
            pointerCount++;
        }

        public TextRange FindWordFromPosition(TextPointer position, string word)
        {
            while (position != null)
            {
                if (position.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.Text)
                {
                    string textRun = position.GetTextInRun(LogicalDirection.Forward);

                    // Find the starting index of any substring that matches "word". 
                    int indexInRun = textRun.IndexOf(word, StringComparison.OrdinalIgnoreCase);
                    if (indexInRun >= 0)
                    {
                        TextPointer start = position.GetPositionAtOffset(indexInRun);
                        if (start == null) return null;
                        TextPointer end = start.GetPositionAtOffset(word.Length);
                        return new TextRange(start, end);
                    }
                }

                position = position.GetNextContextPosition(LogicalDirection.Forward);
            }

            // position will be null if "word" is not found. 
            return null;
        } 


        private void textBoxSearchBox_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Return)
            {
                lastDoc = -2;
                if (lsaSpace != null)
                {
                    List<int> files = new List<int>();
                    var wordString = textBoxSearchBox.Text.ToLower();
                    for(int i = 0; i < lsaSpace.FileNames.Length; i++)
                    {
                        var fileName = lsaSpace.FileNames[i];
                        using(StreamReader stream = File.OpenText(fileName))
                        {
                            char c;
                            int pos = 0;
                            while (!stream.EndOfStream)
                            {
                                c = (char) stream.Read();
                                if (char.ToLower(c) == wordString[pos])
                                {
                                    pos++;
                                    if (pos == wordString.Length)
                                    {
                                        files.Add(i);
                                        break;
                                    }
                                } else
                                {
                                    pos = 0;
                                }
                            }
                        }
                    }
                    if (files.Count == 0)
                    {
                        SoundPlayer simpleSound = new SoundPlayer(@"Sounds\wordNotFoundInCorpus.wav");
                        simpleSound.Play();

                        listViewDocuments.Items.Clear();
                        return;
                    }

                    string[] filePaths = new string[files.Count];
                    for (int i = 0; i < files.Count; i++)
                    {
                        filePaths[i] = lsaSpace.FileNames[files[i]];
                    }

                    FilePaths = filePaths;
                    listViewDocuments.Items.Clear();
                    FillDocumentsList();
                }
                else
                {
                    MessageBox.Show("Трябва да заредите корпус.");
                }
            }
        }

        public void FillDocumentsList()
        {
            for (int i = 0; i < FilePaths.Length; i++)
            {
                listViewDocuments.Items.Add(new KeyValuePair<int, string>(i + 1, FilePaths[i].Split('\\').Last()));
            }
        }

        public void InitializeSearch()
        {
            var a = PresentationSource.CurrentSources.GetEnumerator();
            a.MoveNext();
            textBoxSearchBox_KeyDown(this, new KeyEventArgs(Keyboard.PrimaryDevice, (PresentationSource)a.Current, 0, Key.Enter));
        }

        private void listViewDocuments_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            if (lastDoc == listViewDocuments.SelectedIndex) { ScrollToNext(richTextBoxPreview);
                return;
            }

            richTextBoxPreview.Document.Blocks.Clear();

            if (listViewDocuments.SelectedIndex == -1) return;
            StreamReader streamReader = new StreamReader(FilePaths[listViewDocuments.SelectedIndex]);
            string text = streamReader.ReadToEnd();
            streamReader.Close();
            TextBox tb = new TextBox {Text = text};

            richTextBoxPreview.AppendText(text);
            DoSearch(richTextBoxPreview, textBoxSearchBox.Text, true);

            lastDoc = listViewDocuments.SelectedIndex;
            ScrollToNext(richTextBoxPreview);
        }

        private void richTextBoxPreview_KeyDown(object sender, KeyEventArgs e)
        {

        }

        private void addEntity_Click(object sender, RoutedEventArgs e)
        {
            string entity = tbCurrentSelection.Text.Trim();
            byte category = 0;
            if (lsaSpace.Entities.ContainsKey(entity))
            {
                MessageBox.Show("Вече съществува такъв обект.");
                tbCurrentSelection.Text = "";
                return;
            }
            listView.Items.Add(new KeyValuePair<string, byte>(entity, category));
            lsaSpace.Entities.Add(entity, category);
            tbCurrentSelection.Text = "";
        }

        private void clearEntity_Click(object sender, RoutedEventArgs e)
        {
            listView.Items.Clear();
            listView.Items.Refresh();
        }

        private void richTextBoxPreview_SelectionChanged(object sender, RoutedEventArgs e)
        {
            tbCurrentSelection.Text = richTextBoxPreview.Selection.Text;
        }

        private void deleteEntity_Click(object sender, RoutedEventArgs e)
        {
            if (listView.SelectedIndex == -1) return;
            lsaSpace.Entities.Remove(((KeyValuePair<string, byte>) listView.SelectedItem).Key);
            listView.Items.Remove(listView.Items[listView.SelectedIndex]);
            listView.Items.Refresh();
        }

        private void MenuItem_Click(object sender, RoutedEventArgs e)
        {
            addEntity_Click(sender, e);
        }

        private void comboBoxCategory_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (listView.SelectedItem == null || comboBoxCategory.SelectedItem == null) return;
            var a = ((KeyValuePair<string, byte>) listView.SelectedItem);
            lsaSpace.Entities[a.Key] =
                byte.Parse((string) ((ComboBoxItem) comboBoxCategory.SelectedItem).Content);
            listView.Items.Insert(listView.SelectedIndex + 1, new KeyValuePair<string, byte>(a.Key, lsaSpace.Entities[a.Key]));
            listView.Items.RemoveAt(listView.SelectedIndex);
        }
    }
}
